package com.mongo.config;

import com.mongo.annotation.EncryptField;
import com.mongo.annotation.Mapper;
import com.mongo.proxy.MongoServiceProxy;
import com.mongo.service.MongoMapper;
import com.mongo.service.impl.MongoMapperImpl;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.Document;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.Objects;

/**
 * mongoMapper代理对象,最终功能由{@link MongoMapperImpl 实现}
 * @author xiazhun
 * @create 2022/9/15
 */
public class ServiceProxyFactoryBean<T> implements FactoryBean<T> {
    @Autowired
    private MongoTemplate mongoTemplate;

    private Class<T> interfaces;

    public ServiceProxyFactoryBean(Class<T> interfaces) {
        this.interfaces = interfaces;
    }

    @Override
    @SuppressWarnings("all")
    public T getObject() throws Exception {
        Mapper annotation = AnnotationUtils.findAnnotation(interfaces, Mapper.class);
        Class<?> type = null;
        MongoMapperImpl mapper = null;
        if (Objects.nonNull(annotation)){
            ResolvableType resolvableType = ResolvableType.forClass(interfaces);
            ResolvableType[] resolvableTypes = resolvableType.getInterfaces();
            for (ResolvableType resType : resolvableTypes) {
                if (MongoMapper.class.isAssignableFrom(resType.toClass())){
                    type = resType.getGeneric(0).resolve();
                }
            }
            if (null == type){
                throw new RuntimeException(interfaces.getName() + "必须实现MongoMapper接口");
            }
            Document mongo = type.getAnnotation(Document.class);
            if (Objects.nonNull(mongo)){
                boolean encrypt = isEncrypt(type);
                mapper = new MongoMapperImpl(mongoTemplate,encrypt);
                mapper.setClazz(type);
            }
        }

        return (T) Proxy.newProxyInstance(interfaces.getClassLoader(), new Class[]{interfaces},
                new MongoServiceProxy<>(interfaces,mapper));
    }

    @Override
    public Class<?> getObjectType() {
        return interfaces;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    private boolean isEncrypt(Class type){
        Field[] declaredFields = type.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //如果实体类存在加密注解则将encrypt置为true
            EncryptField annotation = declaredField.getAnnotation(EncryptField.class);
            if (null != annotation) {
                return true;
            }
        }
        return false;
    }
}
